package com.agan.limit.manager;

import com.agan.limit.aop.Limit;
import com.agan.limit.exception.RedisLimitException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * Redis 限流管理器实现类
 * @author weicj
 * @since 2025.01.24
 */
@Slf4j
public class RedisLimiter implements LimiterManager {

    private final StringRedisTemplate stringRedisTemplate;

    private final DefaultRedisScript<Long> redisScript;

    // 构造方法，注入 Redis 模板
    public RedisLimiter(StringRedisTemplate stringRedisTemplate, DefaultRedisScript<Long> redisScript) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.redisScript = redisScript;
    }

    // 尝试访问接口，实现限流逻辑
    @Override
    public boolean tryAccess(Limit limiter) {

        // 获取限流的 key，不能为空
        String key = limiter.key();
        if (StringUtils.isEmpty(key)) {
            throw new RedisLimitException( "redis limiter key cannot be null" );
        }

        // 创建一个 Redis 键的列表，后续会传给 Lua 脚本
        List<String> keys = new ArrayList<>();
        keys.add(key);

        // 获取限流的最大访问次数（每秒允许的请求数）
        double limit = limiter.limitNum();

        // 获取该 key 的过期时间
        long expire = limiter.expire();

        // 执行 Lua 脚本，返回当前的访问次数
        Long count = stringRedisTemplate.execute(redisScript, keys, String.valueOf(limit), String.valueOf(expire));

        // 打印当前访问次数和对应的 key，便于调试
        log.debug( "Access try count is {} for key={}", count, key );

        // 如果 count 为 null 或 0，表示限流触发，无法继续访问
        return count != null && count != 0;
    }

}
